package org.lep.leetcode.constructbinarytree;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Source : https://oj.leetcode.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/
 *
 * Created by lverpeng on 2017/8/13.
 *
 * Given inorder and postorder traversal of a tree, construct the binary tree.
 *
 * Note:
 * You may assume that duplicates do not exist in the tree.
 */
public class ConstructFromInorderAndPostorder {


    /**
     * 根据中序和后序遍历结果构造原来的二叉树
     *
     * inorder:left/root/right
     * postorder:left/right/root
     *
     * @param inorderArr
     * @param postorderArr
     * @return
     */
    public TreeNode build (char[] inorderArr, char[] postorderArr) {
        return buildByRecursion(inorderArr, 0, inorderArr.length-1, postorderArr, 0, postorderArr.length-1);
    }

    public TreeNode buildByRecursion (char[] inorderArr, int inStart, int inEnd,
                                      char[] postorderArr, int postStart, int postEnd) {
        if (inStart > inEnd || postStart > postEnd) {
            return null;
        }

        TreeNode root = new TreeNode(postorderArr[postEnd] - '0');
        int rootIndex = -1;
        for (int i = inStart; i <= inEnd; i++) {
            if (inorderArr[i] == postorderArr[postEnd]) {
                rootIndex = i;
                break;
            }
        }
        if (rootIndex < 0) {
            return null;
        }
        int leftTreeSize = rootIndex - inStart;
        int rightTreeSize = inEnd - rootIndex;
        root.leftChild = buildByRecursion(inorderArr, inStart, rootIndex-1,
                postorderArr, postStart, postStart + leftTreeSize-1);
        root.rightChild = buildByRecursion(inorderArr, inEnd-rightTreeSize+1, inEnd,
                postorderArr, postStart+leftTreeSize, postEnd-1);
        return root;
    }

    /**
     * 使用广度优先遍历将数转化为数组
     *
     * @param root
     * @param chs
     */
    public void binarySearchTreeToArray (TreeNode root, List<Character> chs) {
        if (root == null) {
            chs.add('#');
            return;
        }
        List<TreeNode> list = new ArrayList<TreeNode>();
        int head = 0;
        int tail = 0;
        list.add(root);
        chs.add((char) (root.value + '0'));
        tail ++;
        TreeNode temp = null;

        while (head < tail) {
            temp = list.get(head);
            if (temp.leftChild != null) {
                list.add(temp.leftChild);
                chs.add((char) (temp.leftChild.value + '0'));
                tail ++;
            } else {
                chs.add('#');
            }
            if (temp.rightChild != null) {
                list.add(temp.rightChild);
                chs.add((char)(temp.rightChild.value + '0'));
                tail ++;
            } else {
                chs.add('#');
            }
            head ++;
        }
    }
    private class TreeNode {
        TreeNode leftChild;
        TreeNode rightChild;
        int value;

        public TreeNode(int value) {
            this.value = value;
        }

        public TreeNode() {

        }
    }

    public static void main(String[] args) {
        /*
         *     3
         *    / \
         *   9  2
         *     /  \
         *    1   7
         */

        ConstructFromInorderAndPostorder constructFromInorderAndPostorder = new ConstructFromInorderAndPostorder();
        char[] inorderArr = new char[] {'9','3','1','2','7'};
        char[] postorderArr = new char[]{'9','1','7','2','3'};


        TreeNode root = constructFromInorderAndPostorder.build(inorderArr, postorderArr);
        List<Character> chs = new ArrayList<Character>();
        constructFromInorderAndPostorder.binarySearchTreeToArray(root, chs);
        System.out.println(Arrays.toString(chs.toArray(new Character[chs.size()])));

    }

}
